package services

import (
	"context"
	"gorm.io/gorm"
	"my-gin-tiktok/app/daos"
	"my-gin-tiktok/app/models"
	"my-gin-tiktok/global"
)

type videoService struct{}

var VideoService = new(videoService)

// CreateVideo 用户上传视频
func (s *videoService) CreateVideo(ctx context.Context, userID int64, title, playUrl, coverUrl string) error {
	video := models.Video{UserID: userID, Title: title, PlayURL: playUrl, CoverURL: coverUrl}
	err := global.App.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		err := tx.Create(&video).Error
		if err != nil {
			return err
		}

		err = tx.Model(models.User{}).Exec("update user set work_count = work_count + 1").Error
		if err != nil {
			return err
		}
		return nil
	})
	return err
}

// UpdateVideo 更新视频
func (s *videoService) UpdateVideo(ctx context.Context, userID, videoID, title, playUrl, coverUrl string) error {
	var video models.Video
	err := global.App.DB.WithContext(ctx).Where("id = ? and user_id = ?", videoID, userID).First(&video).Error
	if err != nil {
		return err
	}

	video.Title = title
	video.PlayURL = playUrl
	video.CoverURL = coverUrl
	return global.App.DB.WithContext(ctx).Save(&video).Error
}

// DeleteVideo 删除视频
func (s *videoService) DeleteVideo(ctx context.Context, userID, videoID int64) error {
	var video models.Video
	err := global.App.DB.WithContext(ctx).Where("id = ? and video_id = ?", videoID, userID).Error
	if err != nil {
		return err
	}

	err = global.App.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		err = tx.Delete(&video).Error
		if err != nil {
			return err
		}

		err = tx.Model(models.User{}).Exec("update user set work_count = work_count - 1").Error
		if err != nil {
			return err
		}
		return nil
	})
	return err
}

// GetVideo 视频详情
func (s *videoService) GetVideo(ctx context.Context, videoID int64) (*daos.Video, error) {
	var video models.Video
	err := global.App.DB.WithContext(ctx).First(&video, videoID).Error
	if err != nil {
		return nil, err
	}

	var user models.User
	err = global.App.DB.WithContext(ctx).First(&user, video.UserID).Error
	if err != nil {
		return nil, err
	}

	var favVideoCount int64
	err = global.App.DB.WithContext(ctx).Model(&models.Favorite{}).Where("video_id = ?").Count(&favVideoCount).Error
	if err != nil {
		return nil, err
	}

	var commentCount int64
	err = global.App.DB.WithContext(ctx).Model(&models.Comment{}).Where("video_id = ?", videoID).Count(&commentCount).Error
	if err != nil {
		return nil, err
	}

	return &daos.Video{
		ID:           video.ID,
		Title:        video.Title,
		PlayURL:      video.PlayURL,
		CoverURL:     video.CoverURL,
		UserID:       user.ID,
		UserName:     user.Name,
		LikeCount:    favVideoCount,
		CommentCount: commentCount,
	}, nil
}

// ListVideo 视频列表
func (s *videoService) ListVideo(ctx context.Context) ([]*daos.Video, error) {
	var videos []*models.Video
	err := global.App.DB.WithContext(ctx).Order("id desc").Find(&videos).Error
	if err != nil {
		return nil, err
	}
	videoIDs := make([]int64, len(videos))
	for i, video := range videos {
		videoIDs[i] = video.ID
	}

	userMap := make(map[int64]*models.User, len(videos))
	userIDs := make([]int64, 0, len(videos))
	for i, video := range videos {
		userIDs[i] = video.UserID
	}
	var users []*models.User
	err = global.App.DB.WithContext(ctx).Exec("select user_id, count(user_id) from user where id in (?)", userIDs).Find(&users).Error
	if err != nil {
		return nil, err
	}
	for _, user := range users {
		userMap[user.ID] = user
	}

	favVideoMap := make(map[int64]int64, len(videos))
	err = global.App.DB.WithContext(ctx).Exec("select video_id, count(video_id) from favorite where video_id in (?)", videoIDs).Find(&favVideoMap).Error
	if err != nil {
		return nil, err
	}

	commentVideoMap := make(map[int64]int64, len(videos))
	err = global.App.DB.WithContext(ctx).Exec("select video_id, count(video_id) from comment where video_id in (?)", videoIDs).Find(&commentVideoMap).Error
	if err != nil {
		return nil, err
	}

	videoList := make([]*daos.Video, 0, len(videos))
	for i, video := range videos {
		videoList[i] = &daos.Video{
			ID:           video.ID,
			Title:        video.Title,
			PlayURL:      video.PlayURL,
			CoverURL:     video.CoverURL,
			UserID:       video.UserID,
			UserName:     userMap[video.UserID].Name,
			LikeCount:    favVideoMap[video.ID],
			CommentCount: commentVideoMap[video.ID],
		}
	}
	return videoList, nil
}
